package com.yesep.learn.hik.handle;

import java.io.IOException;
import java.util.*;

import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSONArray;
import com.yesep.learn.hik.model.Command;
import com.yesep.learn.hik.model.Hik;
import com.yesep.learn.hik.model.R;
import com.yesep.learn.hik.sdk.*;
import com.yesep.learn.hik.sdk.FPlayDataCallBack;
import com.yesep.learn.hik.sdk.FRealDataCallBack;
import com.yesep.learn.hik.utils.DateUtil;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sun.jna.NativeLong;
import com.yesep.learn.hik.sdk.HCNetSDK.NET_DVR_CLIENTINFO;

import javax.websocket.Session;

/**
 * @Description: 海康处理
 */
@Data
public class HikHandle {
	private static final Logger log = LoggerFactory.getLogger(HikHandle.class);

	private String sid;

	private Hik hik;

	private boolean bRecordVideo;
	//会话
	private Session session;
	//播放句柄
	private NativeLong m_lPlayHandle;
	//用户句柄
	private NativeLong userId;

	//预览句柄
	private NativeLong lRealHandle;
	//最后登录时间
	private Date lastTime;

	public HikHandle() {
	}

	public HikHandle(Hik hik) throws Exception {
		//初始化SDK
		SDKUtils.initSDK();
		this.hik = hik;
	}

	//执行
	public void execute(Command command) {
		int commandCode = command.getCommandCode();
		log.info("当前[{}]执行的是[{}]", command.toString(), commandCode);
		switch (commandCode) {
		case 1: //云台 控制
			this.ptzContrl(command);
			break;
		case 2: //预览
			this.realPlay(command);
			break;
		case 3: //录像
			this.recordVideo();
			break;
		case 4: //抓图
			this.captureJPEGPicture();
			break;
		case 5: //搜索录像文件
			this.searchPlayBack(command);
			break;
		case 6: //播放回放
			this.playBack(command);
			break;
		default:
			break;
		}
		//获取错误编号  0 无错误 ,其他错误代码参考网络通讯库错误码列表
		int errorCode = SDKUtils.getHCNetSDK().NET_DVR_GetLastError();
		log.info("当前[{}]执行结果为[{}]", commandCode, errorCode);
		showErrorMsg(errorCode);
	}

	//显示错误提示
	public void showErrorMsg(int errorCode) {
		log.info("当前错误码[{}]", errorCode);
		if (Objects.equals(errorCode, 0))
			return;
		String msg = null;
		switch (errorCode) {
		case 1:
			msg = "用户名密码错误";
			break;
		case 2:
			msg = "权限不足";
			break;
		case 3:
			msg = "SDK未初始化";
			break;
		case 4:
			msg = "通道号错误";
			break;
		case 12:
			msg = "请先预览,再录像";
			break;
		default:
			msg = "联系管理员";
			break;
		}

		if (session.isOpen()) {
			String toJson = R.me(1, msg, 1, null).toJson();
			try {
				session.getBasicRemote().sendText(toJson);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	//播放回放
	public void playBack(Command command) {
		NativeLong lChannel = new NativeLong(hik.getLChannel());
		if (!Objects.equals(command.getPlayBackFileName(), null)) { //按文件名
			m_lPlayHandle = SDKUtils.getHCNetSDK().NET_DVR_PlayBackByName(userId, command.getPlayBackFileName(), null);
		} else { //按时间
			HCNetSDK.NET_DVR_FILECOND dvrFilecond = DateUtil.convertDvrFilecondByString("2019-9-15 00:00:00", "2019-9-16 15:46:14");
			m_lPlayHandle = SDKUtils.getHCNetSDK().NET_DVR_PlayBackByTime(userId, lChannel, dvrFilecond.struStartTime, dvrFilecond.struStopTime, null);
		}
		//控制回放状态
		boolean backControlV40 = SDKUtils.getHCNetSDK().NET_DVR_PlayBackControl(m_lPlayHandle, HCNetSDK.NET_DVR_PLAYSTART, 0, null);
		System.out.println("backControlV40 = " + backControlV40);

		//设置回放回调
		boolean playDataCallBack = SDKUtils.getHCNetSDK().NET_DVR_SetPlayDataCallBack(m_lPlayHandle, new FPlayDataCallBack(session), userId.intValue());
		System.out.println("playDataCallBack = " + playDataCallBack);

		if (!backControlV40) {
			System.out.println("回放失败");
			if (session.isOpen()) {
				String toJson = R.me(1, "回放失败", 1, null).toJson();
				try {
					session.getBasicRemote().sendText(toJson);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	//搜索录像文件
	public void searchPlayBack(Command command) {
		//起始结束时间
		Date struBeginTime = command.getStruBeginTime();
		Date struEndTime = command.getStruEndTime();

		//按时间搜索直接播放
		if (!Objects.equals(struBeginTime, null) && !Objects.equals(struEndTime, null)) {
			playBack(command);
		} else { //按文件搜索
			searchPlayBackByFile();
		}
	}

	//按时间或文件名进行文件搜索
	public boolean searchPlayBackByFile() {
		HCNetSDK.NET_DVR_FILECOND dvrFilecond = DateUtil.convertDvrFilecondByString("2019-9-1 09:26:27", "2019-9-12 09:26:31");
		dvrFilecond.lChannel = new NativeLong(hik.getLChannel());
		dvrFilecond.dwFileType = 0;
		dvrFilecond.dwUseCardNo = 0;

		//搜索文件
		NativeLong lFindFile = SDKUtils.getHCNetSDK().NET_DVR_FindFile_V30(userId, dvrFilecond);
		System.out.println("lFindFile = " + lFindFile);

		HCNetSDK.NET_DVR_FINDDATA_V30 strFile = new HCNetSDK.NET_DVR_FINDDATA_V30();
		List<Vector> playBacks = new LinkedList<>();

		NativeLong lnext = null;
		while (true) {
			lnext = SDKUtils.getHCNetSDK().NET_DVR_FindNextFile_V30(lFindFile, strFile);
			if (lnext.longValue() == HCNetSDK.NET_DVR_FILE_SUCCESS) {
				//添加录像信息
				Vector<String> newRow = new Vector<String>();
				newRow.add(new String(strFile.sFileName).split("\0", 2)[0]);
				newRow.add(strFile.struStartTime.toStringTime());
				newRow.add(strFile.struStopTime.toStringTime());
				playBacks.add(newRow);
			} else {
				if (lnext.longValue() == HCNetSDK.NET_DVR_ISFINDING) {//搜索中
					System.out.println("搜索中");
					continue;
				} else {
					if (lnext.longValue() == HCNetSDK.NET_DVR_FILE_NOFIND) {
						System.out.println("没有搜到文件");
						return false;
					} else {
						System.out.println("搜索文件结束");
						boolean flag = SDKUtils.getHCNetSDK().NET_DVR_FindClose_V30(lFindFile);

						if (!flag) {
							System.out.println("结束搜索失败");
							return false;
						}
						String toJSONString = JSONArray.toJSONString(playBacks);
						String json = R.me(5, "搜索成功", 1, toJSONString).toJson();
						if (session.isOpen()) {
							try {
								session.getBasicRemote().sendText(json);
							} catch (IOException e) {
								e.printStackTrace();
							}
							return true;
						}
					}
				}
			}
		}
	}

	//截图
	public boolean captureJPEGPicture() {
		HCNetSDK.NET_DVR_JPEGPARA lpJpegPara = new HCNetSDK.NET_DVR_JPEGPARA();
		lpJpegPara.wPicQuality = 0;
		lpJpegPara.wPicSize = 3;

		//创建文件夹
		FileUtil.mkdir(SDKUtils.getImgPath());

		String imgPath = System.currentTimeMillis() + ".JPEG";
		//图片保存全路径
		String img = SDKUtils.getImgPath() + imgPath;
		//截图
		boolean captureJEGP = SDKUtils.getHCNetSDK().NET_DVR_CaptureJPEGPicture(userId, new NativeLong(1), lpJpegPara, img);
		if (captureJEGP) {
			System.out.println("截图成功");
			if (session.isOpen()) {
				try {
					String toJson = R.me(2, "截图成功", 1, imgPath).toJson();
					session.getBasicRemote().sendText(toJson);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		} else {
			System.out.println("截图失败");
		}
		return captureJEGP;
	}

	//预览
	public NativeLong realPlay(Command command) {
		int isPreView = command.getIsPreView();
		if (Objects.equals(isPreView, 1)) {
			FRealDataCallBack fRealDataCallBack = new FRealDataCallBack(session);
			lRealHandle = this.realPlay(1, fRealDataCallBack, userId);//预览
		} else { //停止预览
			this.stopRealPlay();
		}
		return lRealHandle;
	}

	//注册设备
	public NativeLong login() {
		NativeLong lUserId = SDKUtils.getHCNetSDK().NET_DVR_Login_V30(hik.getIp(), hik.getPort(), hik.getUserName(), hik.getPassword(), hik.getDeviceInfo());
		this.userId = lUserId;
		return lUserId;
	}

	public NET_DVR_CLIENTINFO channel(Integer channelId) {
		HCNetSDK.NET_DVR_CLIENTINFO m_strClientInfo = new HCNetSDK.NET_DVR_CLIENTINFO();
		m_strClientInfo.lChannel = new NativeLong(channelId);
		return m_strClientInfo;
	}

	//预览
	public NativeLong realPlay(Integer channelId, HCNetSDK.FRealDataCallBack_V30 fRealDataCallBack_V30, NativeLong userId) {
		NativeLong lRealHandle = SDKUtils.getHCNetSDK().NET_DVR_RealPlay_V30(userId, channel(channelId), fRealDataCallBack_V30, null, true);
		return lRealHandle;
	}

	//录像
	public void recordVideo() {
		String msg = null;
		//创建文件夹
		FileUtil.mkdir(SDKUtils.getVideoPath());
		String video = System.currentTimeMillis() + ".mp4";
		System.out.println("video = " + video);
		String videoPath = SDKUtils.getVideoPath() + video;
		try {
			if (!bRecordVideo) {
				//录像
				boolean startVideo = SDKUtils.getHCNetSDK().NET_DVR_SaveRealData(userId, videoPath);
				System.out.println("startVideo = " + startVideo);
				if (!startVideo) {
					if (session.isOpen()) {
						String json = R.me(1, "录像失败", 1, null).toJson();
						session.getBasicRemote().sendText(json);
					}
					log.error("录像失败");
					return;
				}
				msg = "开始录像";
				System.out.println("开始录像");
				bRecordVideo = true;
				if (session.isOpen()) {
					String json = R.me(4, msg, 1, video).toJson();
					try {
						session.getBasicRemote().sendText(json);
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			} else {
				//停止录像
				boolean endVideo = SDKUtils.getHCNetSDK().NET_DVR_StopSaveRealData(lRealHandle);
				if (!endVideo) {
					if (session.isOpen()) {
						String json = R.me(1, "录像停止失败", 1, null).toJson();
						session.getBasicRemote().sendText(json);
					}
					log.error("结束录像失败");
					return;
				}
				log.info("结束录像");
				bRecordVideo = false;
				msg = "录像成功";
				if (session.isOpen()) {
					String json = R.me(4, msg, 2, null).toJson();
					try {
						session.getBasicRemote().sendText(json);
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	/**
	 * 根据参数 决定是否需要预览、速度
	 *
	 * @param command
	 * @return
	 */
	public boolean ptzContrl(Command command) {
		if ("1".equals(command.getIsPreView())) { //需要预览
			if (Objects.equals(command.getDwSpeed(), 0)) { //不带速度的云台控制
				return SDKUtils.getHCNetSDK().NET_DVR_PTZControl(getLRealHandle(), command.getDwPTZCommand(), command.getDwStop());
			} else {
				return SDKUtils.getHCNetSDK().NET_DVR_PTZControlWithSpeed(getLRealHandle(), command.getDwPTZCommand(), command.getDwStop(), command.getDwSpeed());
			}
		} else {
			if (Objects.equals(command.getDwSpeed(), 0)) {
				return SDKUtils.getHCNetSDK().NET_DVR_PTZControl_Other(userId, new NativeLong(hik.getLChannel()), command.getDwPTZCommand(), command.getDwStop());
			} else {
				return SDKUtils.getHCNetSDK().NET_DVR_PTZControlWithSpeed_Other(userId, new NativeLong(hik.getLChannel()), command.getDwPTZCommand(), command.getDwStop(), command.getDwSpeed());
			}
		}
	}

	//停止预览
	public boolean stopRealPlay() {
		return SDKUtils.getHCNetSDK().NET_DVR_StopRealPlay(getLRealHandle());
	}
}
